package com.alibaba.otter.manager.web.service;

import com.alibaba.otter.canal.instance.manager.model.Canal;
import com.alibaba.otter.manager.biz.common.exceptions.ManagerException;
import com.alibaba.otter.manager.biz.common.exceptions.RepeatConfigureException;
import com.alibaba.otter.manager.biz.dto.CommonSearchDTO;
import com.alibaba.otter.manager.biz.config.canal.CanalService;
import com.alibaba.otter.manager.biz.config.pipeline.PipelineService;
import com.alibaba.otter.manager.web.dto.CanalDTO;
import com.alibaba.otter.manager.web.dto.CanalParameterDTO;
import com.alibaba.otter.manager.web.mapstruct.CanalMapper;
import com.alibaba.otter.manager.web.utils.PaginationUtil;
import com.alibaba.otter.shared.common.model.config.pipeline.Pipeline;
import com.mybatisflex.core.paginate.Page;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.List;

@Service
public class CanalAggService {

    private final CanalService canalService;

    private final CanalMapper canalMapper;

    private final PipelineService pipelineService;

    public CanalAggService(CanalService canalService, CanalMapper canalMapper, PipelineService pipelineService) {
        this.canalService = canalService;
        this.canalMapper = canalMapper;
        this.pipelineService = pipelineService;
    }


    public CanalDTO findOne(@PathVariable("id") Long id){
        Canal canal = canalService.findById(id);
        CanalDTO canalDTO = canalMapper.toDTO(canal);
        List<Pipeline> pipelines = pipelineService.listByDestinationWithoutOther(canalDTO.getName());
        canalDTO.setPipelines(pipelines);
        canalDTO.setUsed(!pipelines.isEmpty());
        return canalDTO;
    }


    public Page<CanalDTO> list(CommonSearchDTO searchVo, Pageable pageable){
        Page<Canal> canalPage = canalService.canalPage(searchVo, pageable);
        List<Canal> records = canalPage.getRecords();
        List<CanalDTO> canalDTOS = canalMapper.toDTO(records);
        for (CanalDTO canalDTO : canalDTOS) {
            List<Pipeline> pipelines = pipelineService.listByDestinationWithoutOther(canalDTO.getName());
            canalDTO.setPipelines(pipelines);
            canalDTO.setUsed(!pipelines.isEmpty());
        }
        return PaginationUtil.of(canalDTOS,canalPage);
    }



    public void create(CanalDTO canalDTO)  {

        CanalParameterDTO parameter = canalDTO.getCanalParameter();
        if (parameter.getDetectingEnable() && StringUtils.startsWithIgnoreCase(parameter.getDetectingSQL(), "select")) {
            //心跳SQL不允许使用select,建议为insert/update,定时产生binlog数据
            throw new ManagerException("invalid heart beat sql,recommend to use insert/update to periodically generate binlog data");
        }
        Canal canal = canalMapper.toEntity(canalDTO);
        try {
            canalService.create(canal);
        } catch (RepeatConfigureException rce) {
            throw new ManagerException("invalid canal");
        }

        if (parameter.getSourcingType().isMysql() && parameter.getSlaveId() == null) {
            parameter.setSlaveId(10000 + canal.getId());
            // 再次更新一下slaveId
            try {
                canalService.modify(canal);
            } catch (RepeatConfigureException ignored) {

            }
        }
    }


    public void modify(CanalDTO canalDTO) {
        CanalParameterDTO parameter = canalDTO.getCanalParameter();

        if (parameter.getDetectingEnable() && StringUtils.startsWithIgnoreCase(parameter.getDetectingSQL(), "select")) {
            throw new ManagerException("invalid heart beat sql,recommend to use insert/update to periodically generate binlog data");
        }
        Canal canal = canalMapper.toEntity(canalDTO);
        try {
            canalService.modify(canal);
        } catch (RepeatConfigureException rce) {
            throw new ManagerException("invalid canal");
        }
    }

}
